package cn.xinfei.xdecision.engine.runner.executor.strategy.branch;

import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.datax.enums.VirtualDataSourceEnum;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.utils.enums.enginex.ConditionValueTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.context.PipelineContextHolder;
import cn.xinfei.xdecision.engine.runner.context.PipelineMetaInfoContext;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.datax.DataCreditApplyHandler;
import cn.xinfei.xdecision.engine.runner.datax.DataCreditFetchHandler;
import cn.xinfei.xdecision.engine.runner.datax.RiskDataApiAdapter;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.XRunner;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineNodeRunner;
import io.micrometer.core.instrument.Metrics;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.xinfei.xdecision.engine.runner.executor.model.InterVariableConstant.CREDIT_CHANNEL;
import static cn.xinfei.xdecision.engine.runner.executor.model.InterVariableConstant.STAGE;

/**
 * 进入人行征信节点，就直接持久花快照，进入异步状态
 * 本质上，该节点就是个异步标示
 */
@XRunner
@Service
@Slf4j
public class CreditInvestigation extends EngineNodeRunner {

    @Autowired
    private DataCreditApplyHandler dataCreditApplyHandler;

    @Autowired
    private DataCreditFetchHandler dataCreditFetchHandler;

    @Override
    public String getServiceName() {
        return EngineNodeRunner.PRE + NodeTypeEnum.CREDIT_REPORT.getType();
    }

    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(NodeHandler nodeHandler) {
        Map<String, StrategyOutput> outputResult = new HashMap<>();
        StrategyOutput output = new StrategyOutput();
        output.setFieldCode(CREDIT_CHANNEL);
        output.setFieldValue(CREDIT_CHANNEL);
        output.setVarValueType(2);
        output.setStage(3);//输出
        output.setValueType(ConditionValueTypeEnum.VARIABLE.getCode());
        outputResult.put(CREDIT_CHANNEL, output);


        StrategyOutput stage = new StrategyOutput();
        stage.setFieldCode(STAGE);
        stage.setFieldValue(STAGE);
        stage.setVarValueType(2);//string
        stage.setStage(3);//输出
        stage.setValueType(ConditionValueTypeEnum.VARIABLE.getCode());
        outputResult.put(STAGE, stage);


        return outputResult;
    }

    /**
     * 模拟数据
     *
     * @param nodeHandler
     * @return
     */
    @Override
    public Map<String, FieldInfoVo> getInputFieldInfo(NodeHandler nodeHandler) {
        Map<String, FieldInfoVo> fieldVos = new HashMap<>();
        return fieldVos;
    }

//    public void push(NodeHandler nodeHandler)  {
//        EngineNode engineNode = nodeHandler.getEngineNode();
//        String engineCode = engineNode.getEngineCode();
//        String nextNodeCodes = engineNode.getNextNodeCodes();
//        String nodeCode = engineNode.getNodeCode();
//        PipelineContextHolder.pushNodeCode(engineCode, nodeCode, PipelineContextHolder.getDecisionId());
//    }



    @Override
    public StateTransmitModel runNode(NodeHandler nodeHandler) throws Exception {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String engineCode = engineNode.getEngineCode();
        String nodeCode = engineNode.getNodeCode();
        String nextNodeCodes = engineNode.getNextNodeCodes();
        //1.1尝试获取数据
        fetch(engineNode);
        StateTransmitModel stateContext = XDecisionContext.getContext().getStateContext();
        //1.2如果获取到了数据，则继续往后走；如果是获取征信数据失败，则返回终止
        if (stateContext.getEngineResultEnum() == EngineResultEnum.PROCESSING) {
            stateContext.setNextNodeCode(nextNodeCodes);
            log.info("重入人行征信节点 获取变量成功 nodeCode:{},nextNodeCodes:{}", nodeCode, nextNodeCodes);
            PipelineContextHolder.popNodeContextModel(nodeCode);
            return stateContext;
        }
        if (stateContext.getEngineResultEnum() == EngineResultEnum.REVIEW) {
            stateContext.setNextNodeCode(nextNodeCodes);
            log.info("重入人行征信节点 获取变量终止 nodeCode:{},nextNodeCodes:{}", nodeCode, nextNodeCodes);
            PipelineContextHolder.popNodeContextModel(nodeCode);
            return stateContext;
        }
        //其余情况全部重新申请
//        PipelineContextHolder.pushCreditNode(engineCode, EngineResultEnum.CREDIT_PENDING_APPLY.name(), nodeCode, PipelineContextHolder.getDecisionId());
//        PipelineContextHolder.pushNodeCode(engineCode, nextNodeCodes, PipelineContextHolder.getDecisionId());
        if (stateContext.getEngineResultEnum() == EngineResultEnum.CREDIT_PENDING_FETCH) {
            //1.2.1如果是获取征信数据失败，则返回终止，等待重试
            log.info("重入人行征信节点 获取变量失败，等待重试 nodeCode:{},nextNodeCodes:{}", nodeCode, nextNodeCodes);
            return stateContext;
        }
//        PipelineContextHolder.pushNodeCode(engineCode, nodeCode, PipelineContextHolder.getDecisionId());
        return apply(engineNode);
    }

    public StateTransmitModel apply(EngineNode engineNode) throws Exception {
        String nodeCode = engineNode.getNodeCode();
        log.info("执行人行征信节点 runNode nodeCode:{}", nodeCode);
        PipelineMetaInfoContext pipelineMetaInfoContext = XDecisionContext.getContext().getPipelineMetaInfoContext();
        Set<FieldInfoVo> creditField = pipelineMetaInfoContext.getFieldSourceType(VirtualDataSourceEnum.CREDIT_VAR.getCode());
        Set<String> creditFieldCodes = creditField.stream().map(f -> f.getFieldCode()).collect(Collectors.toSet());
        boolean b = dataCreditApplyHandler.queryFieldValue(creditFieldCodes, RiskDataApiAdapter.CollectTypeEnum.CREDIT_APPLY.toString());
        StateTransmitModel stateTransmitModel = XDecisionContext.getContext().getStateContext();
        if (b) {
            log.info("执行人行征信节点 申请变量成功 nodeCode:{}", nodeCode);
            stateTransmitModel.setEngineResultEnum(EngineResultEnum.CREDIT_PENDING_FETCH);
        } else {
            //申请失败，会重试再次申请
            log.error("执行人行征信节点 申请变量失败 nodeCode:{}", nodeCode);
            Metrics.counter("xengine_credit_apply_fail_total").increment();
//            stateTransmitModel.setEngineResultEnum(EngineResultEnum.CREDIT_PENDING_APPLY);
        }
        //执行过人行节点，决策流进入pending状态
        return stateTransmitModel;
    }

    public boolean fetch(EngineNode engineNode) throws Exception {
        String nodeCode = engineNode.getNodeCode();
        log.info("重入人行征信节点，获取征信数据 runNode nodeCode:{}", nodeCode);

        XDecisionContext context = XDecisionContext.getContext();
        PipelineMetaInfoContext pipelineMetaInfoContext = context.getPipelineMetaInfoContext();
        Set<FieldInfoVo> creditField = pipelineMetaInfoContext.getFieldSourceType(VirtualDataSourceEnum.CREDIT_VAR.getCode());
        Set<String> creditFieldCodes = creditField.stream().map(f -> f.getFieldCode()).collect(Collectors.toSet());
        boolean fetchResult = dataCreditFetchHandler.queryFieldValue(creditFieldCodes, RiskDataApiAdapter.CollectTypeEnum.CREDIT_FETCH.toString());
        return fetchResult;
    }

    @Override
    public Map<String, StrategyOutput> getTerminalOutputFieldInfo(NodeHandler nodeHandler) {

        Map<String, StrategyOutput> fieldVos = new HashMap<>();

        return fieldVos;
    }

    @Override
    public boolean terminalCondition(NodeHandler nodeHandler, Map<String, Object> nodeOutput, Map<String, Object> nodeInput) {
        return false;
    }
}
